package com.avic.map.common.scheduled;

import com.avic.map.common.constant.CacheConstant;
import com.avic.map.common.constant.LocalResourceConstant;
import com.avic.map.common.model.MapCommonModel;
import com.avic.map.common.model.enums.EmergencyStateEnums;
import com.avic.map.dal.mapper.CarResourceMapper;
import com.avic.map.dal.mapper.EmergencyMapper;
import com.avic.map.dal.mapper.ShipStaticInfoMapper;
import com.avic.map.dal.mapper.SingleSoldierResourceMapper;
import com.avic.map.dal.model.CarResource;
import com.avic.map.dal.model.Emergency;
import com.avic.map.dal.model.ShipStaticInfo;
import com.avic.map.dal.model.SingleSoldierResource;
import com.avic.map.service.EmergencyService;
import com.avic.map.service.MapShipResourceService;
import com.avic.map.service.ShipStaticInfoService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;

/**
 * @Description 程序启动恢复中断的数据、redis为根源恢复数据
 * 恢复本地静态变量、恢复数据库持久化的数据
 * @Author huangsheng
 * @Date 2018/10/2 17:21
 */
@Slf4j
@Component
public class MapDataRecoverApplicationRunner implements ApplicationRunner {

    @Autowired
    MapShipResourceService mapShipResourceService;

    @Autowired
    EmergencyService emergencyService;

    @Resource(name = CacheConstant.REDIS_BEAN_NAME)
    RedisTemplate redisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private SingleSoldierResourceMapper singleSoldierResourceMapper;

    @Autowired
    private CarResourceMapper carResourceMapper;

    @Autowired
    private EmergencyMapper emergencyMapper;

    @Autowired
    protected ShipStaticInfoService shipStaticInfoService;

    @Autowired
    private ShipStaticInfoMapper shipStaticInfoMapper;

    /**
     * 是否恢复船舶数据
     */
    public static boolean isRecoverShipData = true;


    public static boolean isRecoverSoldierData = true;

    /**
     * 是否恢复车辆数据
     */
    public static boolean isRecoverCarData = true;

    @Override
    public void run(ApplicationArguments var1) throws Exception {

        List<SingleSoldierResource> singleSoldierResources = singleSoldierResourceMapper.queryAllSoldier();
        if (null != singleSoldierResources) {
            singleSoldierResources.forEach(singleSoldierResource -> {
                LocalResourceConstant.SOLDIER_STATE_DB_MAP.put(singleSoldierResource.getPersonnelNumber(), singleSoldierResource);
            });
            log.info("查询出所有单兵数据 {} 条", singleSoldierResources.size());
        }

        List<ShipStaticInfo> shipResources = shipStaticInfoMapper.queryAllVdoShipStaticInfo();
        if (null != shipResources) {
            shipResources.forEach(shipResource -> {
                LocalResourceConstant.SHIP_STATE_DB_MAP.put(shipResource.getShipNumber(), shipResource);
            });
            log.info("查询出所有自己船舶数据 {} 条；把VDO的船舶静态信息放置内存中", shipResources.size());
        }

        List<CarResource> carResources = carResourceMapper.queryAllCar();
        if (null != carResources) {
            carResources.forEach(carResource -> {
                LocalResourceConstant.CAR_STATE_DB_MAP.put(carResource.getCarNumber(), carResource);
            });
            log.info("查询出所有车辆数据 {} 条;", carResources.size());
        }

        List<ShipStaticInfo> vdmShipResources = shipStaticInfoMapper.queryAllVdmShipStaticInfo();
        if (null != vdmShipResources) {
            vdmShipResources.forEach(vdmShipResource -> {
                LocalResourceConstant.VDM_SHIP_STATE_DB_MAP.put(vdmShipResource.getShipNumber(), vdmShipResource);
            });
            log.info("查询出所有VDM船舶数据 {} 条；把VDM的船舶静态信息放置内存中", vdmShipResources.size());
        }

        // 恢复当前是否正在应急
        emergencyRecover();

        if (isRecoverShipData) {
            log.info("MapDataRecoverApplicationRunner 恢复船舶本地数据");
            MapDataRecoverApplicationRunner.isRecoverShipData = false;
            mapShipDataRecover();
        }

        if (isRecoverCarData) {
            log.info("MapDataRecoverApplicationRunner 恢复车辆本地数据");
            MapDataRecoverApplicationRunner.isRecoverCarData = false;
            carDataRecover();
        }

        if (isRecoverSoldierData) {
            log.info("MapDataRecoverApplicationRunner 恢复单兵本地数据");
            MapDataRecoverApplicationRunner.isRecoverSoldierData = false;
            soldierModelDataRecover();
        }
    }

    public void mapShipDataRecover() {
        Map<String, String> mapCommonModelMap =
                redisTemplate.opsForHash().entries(CacheConstant.REDIS_MAP_CURRENT_SHIP_SPACE);
        if (null != mapCommonModelMap) {
            mapCommonModelMap.forEach((key, value) -> {
                try {
                    MapCommonModel shipMapCommonModel = objectMapper.readValue(value, MapCommonModel.class);
                    LocalResourceConstant.SHIP_CURRENT_POSITION_MAP.put(Long.valueOf(key), shipMapCommonModel);
                } catch (IOException e) {
                    log.error("转换发生错误{};", e.getMessage());
                }
            });

            log.info("恢复本地变量数据 {} 条", mapCommonModelMap.size());
        }
    }

    public void carDataRecover() {
        Map<String, String> carCommonModelMap = redisTemplate.opsForHash().entries(CacheConstant.REDIS_MAP_CURRENT_CAR_SPACE);
        if (null != carCommonModelMap) {
            carCommonModelMap.forEach((key, value) -> {
                try {
                    MapCommonModel mapCommonModel = objectMapper.readValue(value, MapCommonModel.class);
                    LocalResourceConstant.CAR_CURRENT_POSITION_MAP.put(key, mapCommonModel);
                    LocalResourceConstant.CAR_CURRENT_STATE_MAP.put(key, mapCommonModel.getStatus());
                } catch (IOException e) {
                    log.error("转换发生错误{};", e.getMessage());
                }
            });
            log.info("恢复本地车辆变量数据 {} 条", carCommonModelMap.size());
        }
    }


    public void soldierModelDataRecover() {
        Map<String, String> soldierCommonModelMap = redisTemplate.opsForHash().entries(CacheConstant.REDIS_MAP_CURRENT_SOLDIER_SPACE);
        if (null != soldierCommonModelMap) {
            soldierCommonModelMap.forEach((key, value) -> {
                try {
                    MapCommonModel mapCommonModel = objectMapper.readValue(value, MapCommonModel.class);
                    LocalResourceConstant.SOLDIER_CURRENT_POSITION_MAP.put(key, mapCommonModel);
                    LocalResourceConstant.SOLDIER_CURRENT_STATE_MAP.put(key, mapCommonModel.getStatus());
                } catch (IOException e) {
                    log.error("转换发生错误{};", e.getMessage());
                }
            });
            log.info("恢复本地单兵变量数据 {} 条", soldierCommonModelMap.size());
        }
    }


    public void emergencyRecover() {
        Emergency emergency = emergencyMapper.queryCurrentEmergency(EmergencyStateEnums.JOIN.getState());
        if (null != emergency) {
            log.info("当前正在应急，恢复内存数据, ID = {}", emergency.getId());

            LocalResourceConstant.EMERGENCY_ID = emergency.getId();
            // 更新本地缓存
            Emergency emergencyCache = new Emergency();
            emergency.setId(emergency.getId());
            emergency.setCreateUserId(emergency.getCreateUserId());

            try {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                emergency.setStartTime(StringUtils.isNotBlank(emergency.getStartTime()) ?
                        String.valueOf(sdf.parse(emergency.getStartTime()).getTime()) : StringUtils.EMPTY);

                LocalResourceConstant.EMERGENCY.put(emergency.getCreateUserId(), emergencyCache);
            } catch (ParseException e) {
            }
        } else {
            log.info("当前未在应急");
        }
    }
}
